﻿using System;
using System.ServiceModel;
using System.Data;
using Skynet.CommonLibrary.ExceptionEx;
using System.Xml.Linq;
using Skynet.CommonLibrary.Extension.Serialize;
using System.Linq.Expressions;

namespace Skynet.CommonLibrary.WCF
{
    internal class DataCenterOperator
    {
        private static DataCenterOperator _instance;
        private DataCenterOperator()
        {
        }

        public static DataCenterOperator Instance
        {
            get { return _instance ?? (_instance = new DataCenterOperator()); }
        }

        private T UsingOpen<T>(Func<DataAccessCenterBase, T> action)
        {
            using (DataAccessCenterBase clientbase = new DataAccessCenterBase())
            {
                try
                {
                    T obj = action(clientbase);
                    clientbase.Close();
                    return obj;
                }
                catch (CommunicationException cx)
                {
                    clientbase.Abort();
                    cx.ProcessException("WCFServiceContract");
                    throw;
                }
                catch (TimeoutException tx)
                {
                    clientbase.Abort();
                    tx.ProcessException("WCFServiceContract");
                    throw;
                }
                catch (Exception ex)
                {
                    clientbase.Close();
                    ex.ProcessException("WCFServiceContract");
                    throw;
                }
            }
        }
        private void UsingOpen(Action<DataAccessCenterBase> action)
        {
            using (DataAccessCenterBase clientbase = new DataAccessCenterBase())
            {
                try
                {
                    action(clientbase);
                }
                catch (CommunicationException cx)
                {
                    clientbase.Abort();
                    cx.ProcessException("WCFServiceContract");
                    throw;
                }
                catch (TimeoutException tx)
                {
                    clientbase.Abort();
                    tx.ProcessException("WCFServiceContract");
                    throw;
                }
                catch (Exception ex)
                {
                    clientbase.Close();
                    ex.ProcessException("WCFServiceContract");
                    throw;
                }
            }
        }

        #region IDataAccessCenter 成员

        public byte[] FindEntity<T>(ParamesEntity data, Expression<Func<T, bool>> expression)
        {
            XElement element = new ExpressionSerializer().Serialize(expression);

            return UsingOpen(operate => operate.FindEntity(data, element.ToString()));
        }

        public byte[] FindData(ParamesEntity data)
        {
            return UsingOpen(operate => operate.FindData(data));
        }

        public bool ModifyData(ParamesEntity data)
        {
            return UsingOpen(operate => operate.ModifyData(data));
        }

        public object GetObject(ParamesEntity data)
        {
            return UsingOpen(operate => operate.GetObject(data));
        }

        public void ExecuteCommand(ParamesEntity data)
        {
            UsingOpen(operate => operate.ExecuteCommand(data));
        }
        #endregion
    }
    internal class DataAccessCenterBase : ClientBase<IDataAccessCenter>, IDataAccessCenter
    {
        internal DataAccessCenterBase()
        {
            this.Open();
        }

        #region IDataAccessCenter 成员

        public byte[] FindEntity(ParamesEntity data, string expression)
        {
            return this.Channel.FindEntity(data, expression);
        }

        public byte[] FindData(ParamesEntity data)
        {
            return this.Channel.FindData(data);
        }


        public bool ModifyData(ParamesEntity data)
        {
            return this.Channel.ModifyData(data);
        }

        public object GetObject(ParamesEntity data)
        {
            return this.Channel.GetObject(data);
        }

        public DataTable GetTable(ParamesEntity data)
        {
            return this.Channel.GetTable(data);
        }

        public void ExecuteCommand(ParamesEntity data)
        {
            this.Channel.ExecuteCommand(data);
        }
        #endregion
    }

}
